﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Web.Security;
using System.Configuration.Provider;
using Db8.Data;
using Db8.DataAccess;

namespace Db8.Providers
{
    public class Db8MembershipProvider : MembershipProvider
    {
        public override string ApplicationName { get; set; }

        public override void Initialize(string name, NameValueCollection config)
        {
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }
            if (string.IsNullOrEmpty(name))
            {
                name = "Db8RoleProvider";
            }
            if (string.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description", "Membership Provider for Db8");
            }

            base.Initialize(name, config);

            ApplicationName = config["applicationName"];
            if (string.IsNullOrEmpty(ApplicationName))
                ApplicationName = "/";
        }

        #region Not supported, functionality implemented by external service (e.g. fb) or not at all

        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            return true;
        }

        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            return true;
        }

        public override bool EnablePasswordReset
        {
            get { return false; }
        }

        public override bool EnablePasswordRetrieval
        {
            get { return false; }
        }

        public override int GetNumberOfUsersOnline()
        {
            return 0;
        }

        public override string GetPassword(string username, string answer)
        {
            return "";
        }

        public override int MaxInvalidPasswordAttempts
        {
            get { return 5; }
        }

        public override int MinRequiredNonAlphanumericCharacters
        {
            get { return 0; }
        }

        public override int MinRequiredPasswordLength
        {
            get { return 0; }
        }

        public override int PasswordAttemptWindow
        {
            get { return 10; }
        }

        public override MembershipPasswordFormat PasswordFormat
        {
            get { return MembershipPasswordFormat.Clear; }
        }

        public override string PasswordStrengthRegularExpression
        {
            get { return ""; }
        }

        public override bool RequiresQuestionAndAnswer
        {
            get { return false; }
        }

        public override string ResetPassword(string username, string answer)
        {
            return "";
        }

        public override bool UnlockUser(string userName)
        {
            return true;
        }

        public override bool ValidateUser(string username, string password)
        {
            return true;
        }

        #endregion

        public override bool RequiresUniqueEmail
        {
            get { return false; }
        }

        public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
        {
            using (Db8Context db = new Db8Context())
            {
                // validate
                status = MembershipCreateStatus.Success;
                if (string.IsNullOrEmpty(username))
                {
                    status = MembershipCreateStatus.InvalidUserName;
                }
                else if (db.Users.Any(u => u.Username == username))
                {
                    status = MembershipCreateStatus.DuplicateUserName;
                }
                else if (providerUserKey == null || !typeof(long).IsAssignableFrom(providerUserKey.GetType()))
                {
                    status = MembershipCreateStatus.InvalidProviderUserKey;
                }
                else if (db.Users.Any(u => u.UserId == (long)providerUserKey))
                {
                    status = MembershipCreateStatus.DuplicateProviderUserKey;
                }

                if (status == MembershipCreateStatus.Success)
                {
                    User user = db.Users.Where(u => u.UserId == (long)providerUserKey).FirstOrDefault();

                    // _update_ if the id already exists!
                    // otherwise create new
                    if (user != null)
                    {
                        user.Username = username;
                        user.Email = email;
                        user.LastActivityDt = DateTime.UtcNow;
                    }
                    else
                    {
                        user = new User()
                        {
                            UserId = (long)providerUserKey,
                            Username = username,
                            LastActivityDt = DateTime.UtcNow,
                            LastUpdatedDt = DateTime.UtcNow,
                            Email = email,
                            Name = username,
                            Score = 1,
                        };
                        db.Users.Add(user);
                    }
                    db.SaveChanges();
                    return CreateMembershipUser(user);
                }
                return null;

            }
        }

        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            //using (Db8Context db = new Db8Context())
            //{
            //    if (deleteAllRelatedData)
            //    {
            //        var users = db.Users
            //            .Include("UserRoles")
            //            .Include("UserRoles.User")
            //            .Include("UserRoles.Role")
            //            .Where(u => u.Username == username);
            //        foreach (var user in users)
            //        {
            //            user.UserRoles.Clear();
            //        }
            //        db.SaveChanges();
            //        return true;
            //    }
            //    else
            //    {
            //    }
            //}
            return false;
        }

        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            using (Db8Context db = new Db8Context())
            {
                MembershipUserCollection muc = new MembershipUserCollection();
                totalRecords = 0;
                var qry = db.Users.Where(u => u.Email.Contains(emailToMatch));
                totalRecords = qry.Count();
                foreach (var user in qry.OrderBy(u => u.UserId).Skip(pageIndex*pageSize).Take(pageSize))
                {
                    muc.Add(CreateMembershipUser(user));
                }
                return muc;
            }
        }

        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            using (Db8Context db = new Db8Context())
            {
                MembershipUserCollection muc = new MembershipUserCollection();
                totalRecords = 0;
                var qry = db.Users.Where(u => u.Username.Contains(usernameToMatch));
                totalRecords = qry.Count();
                foreach (var user in qry.OrderBy(u => u.UserId).Skip(pageIndex * pageSize).Take(pageSize))
                {
                    muc.Add(CreateMembershipUser(user));
                }
                return muc;
            }
        }

        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            using (Db8Context db = new Db8Context())
            {
                MembershipUserCollection muc = new MembershipUserCollection();
                totalRecords = 0;
                var qry = db.Users;
                totalRecords = qry.Count();
                foreach (var user in qry.OrderBy(u => u.UserId).Skip(pageIndex * pageSize).Take(pageSize))
                {
                    muc.Add(CreateMembershipUser(user));
                }
                return muc;
            }
        }


        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            using (Db8Context db = new Db8Context())
            {
                var user = db.Users.Where(u => u.Username == username).FirstOrDefault();
                if (user != null)
                {
                    if (userIsOnline)
                    {
                        user.LastActivityDt = DateTime.UtcNow;
                        db.SaveChanges();
                    }
                    return CreateMembershipUser(user);
                }
            }
            return null;
        }

        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            using (Db8Context db = new Db8Context())
            {
                if (providerUserKey != null && typeof(long).IsAssignableFrom(providerUserKey.GetType()))
                {
                    var user = db.Users.Where(u => u.UserId == (long)providerUserKey).FirstOrDefault();
                    if (user != null)
                    {
                        if (userIsOnline)
                        {
                            user.LastActivityDt = DateTime.UtcNow;
                            db.SaveChanges();
                        }
                        return CreateMembershipUser(user);
                    }
                }
            }
            return null;
        }

        public override string GetUserNameByEmail(string email)
        {
            using (Db8Context db = new Db8Context())
            {
                return db.Users.Where(u => u.Email == email)
                    .Select(u => u.Email)
                    .FirstOrDefault() ?? "";
            }
        }

        public override void UpdateUser(MembershipUser user)
        {
            using (Db8Context db = new Db8Context())
            {
                if (user.ProviderUserKey != null && typeof(long).IsAssignableFrom(user.ProviderUserKey.GetType()))
                {
                    var dbuser = db.Users.Where(u => u.UserId == (long)user.ProviderUserKey).FirstOrDefault();
                    if (dbuser != null)
                    {
                        dbuser.Email = user.Email;
                        if (dbuser.LastActivityDt < user.LastActivityDate)
                            dbuser.LastActivityDt = user.LastActivityDate;
                        if (dbuser.LastActivityDt < user.LastLoginDate)
                            dbuser.LastActivityDt = user.LastLoginDate;
                        dbuser.Username = user.UserName;
                        db.SaveChanges();
                    }
                }
            }
        }


        private MembershipUser CreateMembershipUser(User user)
        {
            return new MembershipUser(Name, user.Username, user.UserId, user.Email, 
                null, null, true, false, DateTime.MinValue, 
                user.LastActivityDt, user.LastActivityDt, DateTime.MinValue, DateTime.MinValue);
        }

        
    }
}
